import unittest
import os
import tempfile
import sqlite3
from app import app

class BlogTestCase(unittest.TestCase):
    
    def setUp(self):
        """测试前设置"""
        self.db_fd, self.db_path = tempfile.mkstemp()
        app.config['DATABASE'] = self.db_path
        app.config['TESTING'] = True
        self.app = app.test_client()
        
        # 初始化测试数据库
        self.init_test_db()
    
    def tearDown(self):
        """测试后清理"""
        os.close(self.db_fd)
        os.unlink(self.db_path)
    
    def init_test_db(self):
        """初始化测试数据库"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 创建文章表
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS articles (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                content TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # 创建评论表
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS comments (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                article_id INTEGER NOT NULL,
                author TEXT NOT NULL,
                content TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (article_id) REFERENCES articles (id) ON DELETE CASCADE
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def test_index_page(self):
        """测试首页访问"""
        response = self.app.get('/')
        self.assertEqual(response.status_code, 200)
        self.assertIn('个人博客'.encode('utf-8'), response.data)
    
    def test_admin_page(self):
        """测试管理后台访问"""
        response = self.app.get('/admin')
        self.assertEqual(response.status_code, 200)
        self.assertIn('管理后台'.encode('utf-8'), response.data)
    
    def test_add_article(self):
        """测试添加文章"""
        response = self.app.post('/add_article', data={
            'title': '测试文章',
            'content': '这是测试内容'
        }, follow_redirects=True)
        
        self.assertEqual(response.status_code, 200)
        
        # 验证文章是否已添加
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM articles WHERE title = ?', ('测试文章',))
        article = cursor.fetchone()
        conn.close()
        
        self.assertIsNotNone(article)
        self.assertEqual(article[1], '测试文章')
        self.assertEqual(article[2], '这是测试内容')
    
    def test_add_article_empty_fields(self):
        """测试添加空文章"""
        response = self.app.post('/add_article', data={
            'title': '',
            'content': ''
        })
        
        self.assertEqual(response.status_code, 400)
    
    def test_article_detail(self):
        """测试文章详情页"""
        # 先添加一篇文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('测试详情', '测试内容'))
        article_id = cursor.lastrowid
        conn.commit()
        conn.close()
        
        # 测试访问详情页
        response = self.app.get('/article/{}'.format(article_id))
        self.assertEqual(response.status_code, 200)
        self.assertIn('测试详情'.encode('utf-8'), response.data)
    
    def test_article_not_found(self):
        """测试访问不存在的文章"""
        response = self.app.get('/article/9999')
        self.assertEqual(response.status_code, 404)
    
    def test_add_comment(self):
        """测试添加评论"""
        # 先添加一篇文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('评论测试', '内容'))
        article_id = cursor.lastrowid
        conn.commit()
        conn.close()
        
        # 添加评论
        response = self.app.post('/add_comment/{}'.format(article_id), data={
            'author': '测试用户',
            'content': '这是一条测试评论'
        }, follow_redirects=True)
        
        self.assertEqual(response.status_code, 200)
        
        # 验证评论是否已添加
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM comments WHERE article_id = ?', (article_id,))
        comment = cursor.fetchone()
        conn.close()
        
        self.assertIsNotNone(comment)
        self.assertEqual(comment[2], '测试用户')
        self.assertEqual(comment[3], '这是一条测试评论')
    
    def test_add_comment_empty_fields(self):
        """测试添加空评论"""
        # 先添加一篇文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('评论测试', '内容'))
        article_id = cursor.lastrowid
        conn.commit()
        conn.close()
        
        # 添加空评论
        response = self.app.post('/add_comment/{}'.format(article_id), data={
            'author': '',
            'content': ''
        })
        
        self.assertEqual(response.status_code, 400)
    
    def test_add_comment_to_nonexistent_article(self):
        """测试向不存在的文章添加评论"""
        response = self.app.post('/add_comment/9999', data={
            'author': '测试用户',
            'content': '测试评论'
        })
        
        self.assertEqual(response.status_code, 404)
    
    def test_edit_article(self):
        """测试编辑文章"""
        # 先添加一篇文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('原始标题', '原始内容'))
        article_id = cursor.lastrowid
        conn.commit()
        conn.close()
        
        # 编辑文章
        response = self.app.post('/edit_article/{}'.format(article_id), data={
            'title': '修改后的标题',
            'content': '修改后的内容'
        }, follow_redirects=True)
        
        self.assertEqual(response.status_code, 200)
        
        # 验证文章是否已更新
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM articles WHERE id = ?', (article_id,))
        article = cursor.fetchone()
        conn.close()
        
        # 验证更新成功
        self.assertIsNotNone(article)
        print("Debug - Article after edit:", article)  # 调试信息
        self.assertEqual(article[1], '修改后的标题')
        self.assertEqual(article[2], '修改后的内容')
    
    def test_delete_article(self):
        """测试删除文章"""
        # 先添加一篇文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('待删除', '内容'))
        article_id = cursor.lastrowid
        conn.commit()
        conn.close()
        
        # 删除文章
        response = self.app.post('/delete_article/{}'.format(article_id), follow_redirects=True)
        self.assertEqual(response.status_code, 200)
        
        # 验证文章是否已删除
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM articles WHERE id = ?', (article_id,))
        article = cursor.fetchone()
        conn.close()
        
        self.assertIsNone(article)
    
    def test_delete_article_with_comments(self):
        """测试删除文章时同时删除相关评论"""
        # 添加文章
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('INSERT INTO articles (title, content) VALUES (?, ?)', 
                       ('测试删除', '内容'))
        article_id = cursor.lastrowid
        
        # 添加评论
        cursor.execute('INSERT INTO comments (article_id, author, content) VALUES (?, ?, ?)', 
                       (article_id, '用户', '评论'))
        conn.commit()
        conn.close()
        
        # 删除文章
        self.app.post('/delete_article/{}'.format(article_id))
        
        # 验证评论是否也被删除
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM comments WHERE article_id = ?', (article_id,))
        comments = cursor.fetchall()
        conn.close()
        
        self.assertEqual(len(comments), 0)

if __name__ == '__main__':
    unittest.main()
